package cgs_map

import (
	"cgs-server/server"
	"cgs-server/server/assets/cgs"
	"cgs-server/server/base"
	"cgs-server/server/model"
	"errors"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
)

type MapRepository interface {
	base.Repository

	// SaveData 保存 map 数据
	SaveData(data *CgsMapData) error
	// RemoveData 删除 map 数据
	RemoveData(id primitive.ObjectID) error
	// GetData 获取 map 数据
	GetData(id primitive.ObjectID) (*CgsMapData, error)

	FindByProjectId(id primitive.ObjectID) (*cgs.CgsProj, error)
	FindBySceneId(id primitive.ObjectID) (*CgsMap, error)
}

func NewMapRepository() MapRepository {
	return &mapRepository{
		RepositoryStruct: base.RepositoryStruct{
			CollectionName: server.CgsMapCollectionName,
		},
	}
}

type mapRepository struct {
	base.RepositoryStruct
}

func (m *mapRepository) FindBySceneId(id primitive.ObjectID) (*CgsMap, error) {
	db, err := server.Mongo()
	if err != nil {
		return nil, err
	}
	filter := bson.M{
		"id": id,
	}
	var result CgsMap
	_, err = db.FindOne(server.CgsMapCollectionName, filter, &result)
	if err != nil {
		return nil, err
	}
	var cgsData CgsMapData
	filter = bson.M{
		"id": result.DataID,
	}
	_, err = db.FindOne(server.CgsMapDataCollectionName, filter, &cgsData)
	if err != nil {
		return nil, err
	}

	result.Data = cgsData.Data

	return &result, err
}

func (m *mapRepository) FindByProjectId(id primitive.ObjectID) (*cgs.CgsProj, error) {
	db, err := server.Mongo()
	if err != nil {
		return nil, err
	}
	filter := bson.M{
		"ID": id,
	}
	var result cgs.CgsProj
	_, err = db.FindOne(server.CgsProjectCollectionName, filter, &result)
	return &result, err
}

func (m *mapRepository) GetData(id primitive.ObjectID) (*CgsMapData, error) {
	if err := m.CheckDB(); err != nil {
		return nil, err
	}

	filter := bson.M{
		"id": id,
	}

	result := &CgsMapData{}

	find, err := m.Mongo.FindOne(server.CgsMapDataCollectionName, filter, result)
	if !find {
		return nil, errors.New("not found")
	}
	return result, err
}

func (m *mapRepository) RemoveData(id primitive.ObjectID) error {
	if err := m.CheckDB(); err != nil {
		return err
	}

	filter := bson.M{
		"id": id,
	}

	_, err := m.Mongo.DeleteOne(server.CgsMapDataCollectionName, filter)
	return err
}

func (m *mapRepository) SaveData(data *CgsMapData) error {
	if err := m.CheckDB(); err != nil {
		return err
	}

	_, err := m.Mongo.InsertOne(server.CgsMapDataCollectionName, data)
	return err
}

func (m *mapRepository) Find(mdl *model.DataUserModel) (interface{}, error) {
	if visualMap, ok := mdl.Data.(*CgsMap); ok {
		if err := m.CheckDB(); err != nil {
			return nil, err
		}
		filter := bson.M{}
		visualMap.ResolveFilter(visualMap, mdl.User, &filter)
		opts := visualMap.ResolveOptions(mdl.Page)
		result := []*CgsMap{}
		err := m.Mongo.FindMany(m.CollectionName, filter, &result, opts)
		return result, err
	} else {
		return nil, model.NewTypeError("VisualMap")
	}
}

func (m *mapRepository) Insert(mdl *model.DataUserModel) error {
	if visualMap, ok := mdl.Data.(*CgsMap); ok {
		if err := m.CheckDB(); err != nil {
			return err
		}
		visualMap.ResolveEntity(visualMap, mdl.User)
		_, err := m.Mongo.InsertOne(m.CollectionName, visualMap)
		return err
	} else {
		return model.NewTypeError("VisualMap")
	}
}

func (m *mapRepository) Update(mdl *model.DataUserModel) error {
	if visualMap, ok := mdl.Data.(*CgsMap); ok {
		if err := m.CheckDB(); err != nil {
			return err
		}
		filter := bson.M{
			"id": visualMap.Id,
		}
		visualMap.ResolveFilter(visualMap, mdl.User, &filter)

		updateOpt := bson.M{}
		if visualMap.Name != "" {
			updateOpt["name"] = visualMap.Name
		}
		if !visualMap.DataID.IsZero() {
			updateOpt["dataID"] = visualMap.DataID
		}
		visualMap.ResolveUpdateCondition(visualMap, mdl.User, &updateOpt)
		update := bson.M{"$set": updateOpt}

		_, err := m.Mongo.UpdateOne(m.CollectionName, filter, update)
		return err
	} else {
		return model.NewTypeError("VisualMap")
	}
}

func (m *mapRepository) Delete(mdl *model.DataUserModel) error {
	if visualMap, ok := mdl.Data.(*CgsMap); ok {
		if err := m.CheckDB(); err != nil {
			return err
		}
		filter := bson.M{"id": visualMap.Id}
		visualMap.ResolveFilter(visualMap, mdl.User, &filter)
		_, err := m.Mongo.DeleteOne(m.CollectionName, filter)
		return err
	} else {
		return model.NewTypeError("VisualMap")
	}
}

func (m *mapRepository) DeleteLogic(mdl *model.DataUserModel) error {
	if visualMap, ok := mdl.Data.(*CgsMap); ok {
		if err := m.CheckDB(); err != nil {
			return err
		}
		filter := bson.M{"id": visualMap.Id}
		visualMap.ResolveFilter(visualMap, mdl.User, &filter)
		set := bson.M{}
		visualMap.DeleteLogic(visualMap, mdl.User, &set)
		update := bson.M{
			"$set": set,
		}
		_, err := m.Mongo.UpdateOne(m.CollectionName, filter, update)
		return err
	} else {
		return model.NewTypeError("VisualMap")
	}
}

func (m *mapRepository) FindOne(mdl *model.DataUserModel) (interface{}, error) {
	if visualMap, ok := mdl.Data.(*CgsMap); ok {
		if err := m.CheckDB(); err != nil {
			return nil, err
		}
		filter := bson.M{"id": visualMap.Id}
		visualMap.ResolveFilter(visualMap, mdl.User, &filter)
		res := &CgsMap{}
		find, err := m.Mongo.FindOne(m.CollectionName, filter, res)
		if !find {
			return nil, errors.New("not found")
		}
		return res, err
	} else {
		return nil, model.NewTypeError("VisualMap")
	}
}
